package com.nlelpct.manage.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nlelpct.manage.constant.ResponseCode;
import com.nlelpct.manage.constant.SysRoleConstant;
import com.nlelpct.manage.constant.SystemConstant;
import com.nlelpct.manage.context.ThreadParameter;
import com.nlelpct.manage.mapper.SysMenuMapper;
import com.nlelpct.manage.mapper.SysRoleMapper;
import com.nlelpct.manage.model.entity.SysMenu;
import com.nlelpct.manage.model.entity.SysRole;
import com.nlelpct.manage.model.entity.SysRoleDept;
import com.nlelpct.manage.model.entity.SysRoleMenu;
import com.nlelpct.manage.model.query.InsertAndUpdateRoleQuery;
import com.nlelpct.manage.model.query.RolePageQuery;
import com.nlelpct.manage.model.vo.*;
import com.nlelpct.manage.service.IRoleService;
import com.nlelpct.manage.service.ISysRoleDeptService;
import com.nlelpct.manage.service.ISysRoleMenuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author :小马
 * @date : 2023-07-20
 */
@Service
@Slf4j
public class RoleServiceImpl implements IRoleService {

    private final SysRoleMapper sysRoleMapper;

    private final ISysRoleDeptService sysRoleDeptService;

    private final ISysRoleMenuService sysRoleMenuService;

    private final SysMenuMapper sysMenuMapper;

    @Autowired
    public RoleServiceImpl(SysRoleMapper sysRoleMapper, ISysRoleDeptService sysRoleDeptService, ISysRoleMenuService sysRoleMenuService, SysMenuMapper sysMenuMapper) {
        this.sysRoleMapper = sysRoleMapper;
        this.sysRoleDeptService = sysRoleDeptService;
        this.sysRoleMenuService = sysRoleMenuService;
        this.sysMenuMapper = sysMenuMapper;
    }

    @Override
    public ResponseResult<PageResultVo<SysRole>> queryRolePageList(RolePageQuery rolePageQuery) {
        String companyId = ThreadParameter.getLocalMap().get(SystemConstant.COMPANY_ID);
        if (ObjectUtil.isEmpty(companyId)) {
            return ResponseResult.error(ResponseCode.ORDINARY_FAIL, "未获取到相关企业信息");
        }
        rolePageQuery.setCompanyId(companyId);
        if (ObjectUtil.isEmpty(rolePageQuery.getOrderField())) {
            rolePageQuery.setOrderField(SysRole.CREATE_TIME);
        }
        if (ObjectUtil.isEmpty(rolePageQuery.getOrderType())) {
            rolePageQuery.setOrderType(SystemConstant.ORDER_DESC);
        }
        Page<SysRole> page = new Page<>(Optional.ofNullable(rolePageQuery.getPageNumber()).orElse(1),
                Optional.ofNullable(rolePageQuery.getPageSize()).orElse(10));
        page = sysRoleMapper.selectRolePage(page, rolePageQuery);
        return ResponseResult.success(new PageResultVo<>(page.getRecords(), page.getTotal()));
    }


    @Override
    public ResponseResult<List<RoleInfoForCompanyVo>> getRoleInfoForCompany() {
        String companyId = ThreadParameter.getLocalMap().get(SystemConstant.COMPANY_ID);
        if (ObjectUtil.isEmpty(companyId)) {
            return ResponseResult.error(ResponseCode.ORDINARY_FAIL, "未获取到相关企业信息");
        }
        List<RoleInfoForCompanyVo> result = sysRoleMapper.selectList(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getCompanyId, companyId)
                .eq(SysRole::getDelFlag, SysRoleConstant.NOT_DELETE))
                .parallelStream().map(role -> {
                    RoleInfoForCompanyVo roleInfoForCompanyVo = new RoleInfoForCompanyVo();
                    roleInfoForCompanyVo.setRoleId(role.getRoleId());
                    roleInfoForCompanyVo.setRoleName(role.getRoleName());
                    return roleInfoForCompanyVo;
                }).collect(Collectors.toList());
        return ResponseResult.success(result);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertRole(InsertAndUpdateRoleQuery insertRoleQuery) {
        HashMap<String, String> localMap = ThreadParameter.getLocalMap();
        String companyId = localMap.get(SystemConstant.COMPANY_ID);
        CompletableFuture<String> nextRoleNumFuture = CompletableFuture.supplyAsync(() -> getNextRoleNum(companyId));
        String employeeId = localMap.get(SystemConstant.EMPLOYEE_ID);
        try {
            SysRole sysRole = new SysRole();
            sysRole.setRoleId(UUID.randomUUID().toString().replaceAll("-", ""));
            sysRole.setCompanyId(companyId);
            sysRole.setRoleName(insertRoleQuery.getRoleName());
            sysRole.setCreateBy(employeeId);
            sysRole.setRoleDesc(insertRoleQuery.getRoleDesc());
            sysRole.setCreateTime(System.currentTimeMillis());
            sysRole.setRoleNum(nextRoleNumFuture.get());
            sysRoleMapper.insert(sysRole);
        } catch (Exception e) {
            log.error("添加失败,出现了异常");
            throw new RuntimeException(e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRole(InsertAndUpdateRoleQuery updateRoleQuery) {
        String employeeId = ThreadParameter.getLocalMap().get(SystemConstant.EMPLOYEE_ID);
        SysRole sysRole = new SysRole();
        sysRole.setRoleId(updateRoleQuery.getRoleId());
        sysRole.setRoleName(updateRoleQuery.getRoleName());
        sysRole.setRoleDesc(updateRoleQuery.getRoleDesc());
        sysRole.setUpdateBy(employeeId);
        sysRole.setUpdateTime(System.currentTimeMillis());
        sysRoleMapper.updateById(sysRole);
    }

    @Override
    public ResponseResult<Boolean> validateRoleName(InsertAndUpdateRoleQuery validateRoleNameQuery) {
        LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysRole::getRoleName, validateRoleNameQuery.getRoleName())
                .eq(SysRole::getCompanyId, ThreadParameter.getLocalData(SystemConstant.COMPANY_ID))
                .eq(SysRole::getDelFlag, SysRoleConstant.NOT_DELETE);
        SysRole sysRole = sysRoleMapper.selectOne(queryWrapper);
        if (ObjectUtil.isEmpty(sysRole)) {
            return ResponseResult.success(true, "角色名称无重复");
        }
        if (sysRole.getRoleId().equals(validateRoleNameQuery.getRoleId())) {
            return ResponseResult.success(true, "角色名称无重复");
        }
        return ResponseResult.success(false, "角色名称重复");
    }


    @Override
    public ResponseResult<DataPermissionsVo> getDataPermissionsByRoleId(String roleId) {
        CompletableFuture<List<SysRoleDept>> listCompletableFuture = CompletableFuture.supplyAsync(() ->
                sysRoleDeptService.list(new LambdaQueryWrapper<SysRoleDept>().eq(SysRoleDept::getRoleId, roleId)));
        SysRole sysRole = sysRoleMapper.selectById(roleId);
        DataPermissionsVo dataPermissionsVo = new DataPermissionsVo();
        dataPermissionsVo.setRoleId(roleId);
        dataPermissionsVo.setDataScope(sysRole.getDataScope());
        dataPermissionsVo.setDeptCheckStrictly(sysRole.getDeptCheckStrictly());
        try {
            List<SysRoleDept> sysRoleDepartments = listCompletableFuture.get();
            if (sysRoleDepartments.size() > 0) {
                dataPermissionsVo.setDepartmentIds(sysRoleDepartments.stream().map(SysRoleDept::getDeptId).collect(Collectors.toList()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseResult.success(dataPermissionsVo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeDataPermissionsByRole(DataPermissionsVo dataPermissionsVo) {
        SysRole sysRole = new SysRole();
        String employeeId = ThreadParameter.getLocalMap().get(SystemConstant.EMPLOYEE_ID);
        String roleId = dataPermissionsVo.getRoleId();
        sysRole.setRoleId(roleId);
        sysRole.setDataScope(dataPermissionsVo.getDataScope());
        sysRole.setDeptCheckStrictly(dataPermissionsVo.getDeptCheckStrictly());
        sysRole.setUpdateTime(System.currentTimeMillis());
        sysRole.setUpdateBy(employeeId);
        sysRoleMapper.updateById(sysRole);
        sysRoleDeptService.removeById(roleId);
        List<String> departmentIds = dataPermissionsVo.getDepartmentIds();
        if (!ObjectUtil.isEmpty(departmentIds) && dataPermissionsVo.getDataScope().equals(SysRoleConstant.DATA_SCOPE_CUSTOM)) {
            List<SysRoleDept> saveData = departmentIds.parallelStream().map(deptId -> {
                SysRoleDept sysRoleDept = new SysRoleDept();
                sysRoleDept.setRoleId(roleId);
                sysRoleDept.setDeptId(deptId);
                return sysRoleDept;
            }).collect(Collectors.toList());
            sysRoleDeptService.saveBatch(saveData);
        }
    }

    @Override
    public ResponseResult<MenuPermissionsVo> getMenuByRoleId(String roleId) {
        String systemId = ThreadParameter.getLocalData(SystemConstant.SYSTEM_ID);
        CompletableFuture<Map<Boolean, List<SysMenu>>> menuTypeMap = CompletableFuture.supplyAsync(() -> sysMenuMapper.selectList(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getSystemId, systemId))
                .parallelStream().collect(Collectors.partitioningBy(menu -> menu.getMenuType() == 3)));
        SysRole sysRole = sysRoleMapper.selectById(roleId);
        List<SysRoleMenu> list = sysRoleMenuService.list(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
        MenuPermissionsVo menuPermissionsVo = new MenuPermissionsVo();
        menuPermissionsVo.setRoleId(roleId);
        menuPermissionsVo.setMenuCheckStrictly(sysRole.getMenuCheckStrictly());
        if (list.size() > 0) {
            List<String> menuIds = new ArrayList<>();
            List<String> buttonIds = new ArrayList<>();
            List<String> systemMenuIds;
            try {
                systemMenuIds = menuTypeMap.get().get(Boolean.FALSE).stream().map(SysMenu::getMenuId).collect(Collectors.toList());
            } catch (Exception e) {
                systemMenuIds = new ArrayList<>();
                e.printStackTrace();
            }
            String menuId;
            for (SysRoleMenu sysRoleMenu : list) {
                menuId = sysRoleMenu.getMenuId();
                if (systemMenuIds.contains(menuId)) {
                    menuIds.add(menuId);
                } else {
                    buttonIds.add(menuId);
                }
            }
            menuPermissionsVo.setMenuIds(menuIds);
            menuPermissionsVo.setButtonIds(buttonIds);
        }
        return ResponseResult.success(menuPermissionsVo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeMenuPermissionsByRole(MenuPermissionsVo menuPermissionsVo) {
        SysRole sysRole = new SysRole();
        String employeeId = ThreadParameter.getLocalMap().get(SystemConstant.EMPLOYEE_ID);
        String roleId = menuPermissionsVo.getRoleId();
        sysRole.setRoleId(roleId);
        sysRole.setMenuCheckStrictly(menuPermissionsVo.getMenuCheckStrictly());
        sysRole.setUpdateTime(System.currentTimeMillis());
        sysRole.setUpdateBy(employeeId);
        sysRoleMapper.updateById(sysRole);
        sysRoleMenuService.removeById(roleId);
        menuPermissionsVo.getMenuIds().addAll(menuPermissionsVo.getButtonIds());
        List<String> menuIds = menuPermissionsVo.getMenuIds();
        if (!ObjectUtil.isEmpty(menuIds)) {
            List<SysRoleMenu> sysRoleMenuList = menuIds.parallelStream().map(menuId -> {
                SysRoleMenu sysRoleMenu = new SysRoleMenu();
                sysRoleMenu.setRoleId(roleId);
                sysRoleMenu.setMenuId(menuId);
                return sysRoleMenu;
            }).collect(Collectors.toList());
            sysRoleMenuService.saveBatch(sysRoleMenuList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeRole(String roleId) {
        // 删除角色表数据 -- 逻辑删除
        SysRole sysRole = new SysRole();
        sysRole.setRoleId(roleId);
        sysRole.setDelFlag(SysRoleConstant.DELETE);
        sysRole.setUpdateTime(System.currentTimeMillis());
        sysRole.setUpdateBy(ThreadParameter.getLocalData(SystemConstant.EMPLOYEE_ID));
        sysRoleMapper.updateById(sysRole);
    }

    @Override
    public ResponseResult<InsertAndUpdateRoleQuery> getRoleInfoByUpdate(String roleId) {
        SysRole sysRole = sysRoleMapper.selectById(roleId);
        InsertAndUpdateRoleQuery insertAndUpdateRoleQuery = new InsertAndUpdateRoleQuery();
        insertAndUpdateRoleQuery.setRoleNum(sysRole.getRoleNum());
        insertAndUpdateRoleQuery.setRoleId(sysRole.getRoleId());
        insertAndUpdateRoleQuery.setRoleName(sysRole.getRoleName());
        insertAndUpdateRoleQuery.setRoleDesc(sysRole.getRoleDesc());
        return ResponseResult.success(insertAndUpdateRoleQuery);
    }

    @Override
    public ResponseResult<Boolean> deleteRoleValidate(String roleId) {
        // todo 流程模块还不存在,所以暂时返回 `TRUE`
        return ResponseResult.success(Boolean.TRUE);
    }

    private String getNextRoleNum(String companyId) {
        String lastRoleNum = sysRoleMapper.getCompanyLastRoleNum(companyId);
        if (ObjectUtil.isEmpty(lastRoleNum)) {
            lastRoleNum = "0";
        }
        String nextNum = String.valueOf(Integer.parseInt(lastRoleNum) + 1);
        StringBuilder nextRoleNum = new StringBuilder();
        for (int i = 0; i < SysRoleConstant.MAX_ROLE_NUMBER - nextNum.length(); i++) {
            nextRoleNum.append("0");
        }
        return nextRoleNum + nextNum;
    }
}
